/*
 * Copyright (C) 2019 ByteDance Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bytedance.scene.animation.animatorexecutor;


import com.bytedance.scene.Scene;
import com.bytedance.scene.State;
import com.bytedance.scene.animation.AnimationInfo;
import com.bytedance.scene.animation.AnimationOrAnimator;
import com.bytedance.scene.animation.NavigationAnimationExecutor;
import com.bytedance.scene.utlity.AnimatorUtility;
import com.bytedance.scene.utlity.CancellationSignal;
import ohos.aafwk.ability.Ability;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.Component;

/**
 * Created by JiangQi on 8/15/18.
 */
public final class AnimationOrAnimatorResourceExecutor extends NavigationAnimationExecutor {
    private AnimationOrAnimator mEnterAnimator;
    private AnimationOrAnimator mExitAnimator;
    private Ability ability;

    public AnimationOrAnimatorResourceExecutor(Ability activity, int enterResId, int exitResId) {
        mEnterAnimator = AnimationOrAnimator.loadAnimation(activity, enterResId);
        mExitAnimator = AnimationOrAnimator.loadAnimation(activity, exitResId);
    }

    private Animator mPushEnter;
    private Animator mPushExit;
    private Animator mPopEnter;
    private Animator mPopExit;
    private boolean isPushToLeft;
    private boolean isPushToRight;

    public AnimationOrAnimatorResourceExecutor(Ability activity, Animator pushEnter, Animator pushExit
            , Animator popEnter, Animator popExit, boolean isPushToLeft,
                                               boolean isPushToRight) {
        this.ability = activity;
        this.mPushEnter = pushEnter;
        this.mPushExit = pushExit;
        this.mPopEnter = popEnter;
        this.mPopExit = popExit;
        this.isPushToLeft = isPushToLeft;
        this.isPushToRight = isPushToRight;
    }

    @Override
    public boolean isSupport(Class<? extends Scene> from, Class<? extends Scene> to) {
        return true;
    }

    @Override
    public void executePushChangeCancelable(final AnimationInfo fromInfo, final AnimationInfo toInfo, final Runnable endAction, CancellationSignal cancellationSignal) {
        // Cannot be placed in onAnimationStart, as there it a post interval, it will splash
        final Component fromView = fromInfo.mSceneView;
        final Component toView = toInfo.mSceneView;

        AnimatorUtility.resetViewStatus(fromView);
        AnimatorUtility.resetViewStatus(toView);
        fromView.setVisibility(Component.VISIBLE);


        if (fromInfo.mSceneState.value < State.VIEW_CREATED.value) {
            mAnimationViewGroup.addComponent(fromView);
        }

        Runnable animationEndAction = new CountRunnable(2, new Runnable() {
            @Override
            public void run() {
                if (!toInfo.mIsTranslucent) {
                    fromView.setVisibility(Component.HIDE);
                }

                AnimatorUtility.resetViewStatus(fromView);
                AnimatorUtility.resetViewStatus(toView);

                if (fromInfo.mSceneState.value < State.VIEW_CREATED.value) {
                    mAnimationViewGroup.removeComponent(fromView);
                }
                endAction.run();
            }
        });

        if (isPushToLeft) {
            toView.setTranslationX(toView.getWidth());
        } else if (isPushToRight) {
//            toView.setTranslationX(0);
        }

        fromView.setTranslationX(fromView.getWidth());
        mEnterAnimator = AnimationOrAnimator.loadAnimation(ability, mPushEnter);
        mExitAnimator = AnimationOrAnimator.loadAnimation(ability, mPushExit);

        mEnterAnimator.addEndAction(animationEndAction);
        mExitAnimator.addEndAction(animationEndAction);

        mEnterAnimator.start(toView);
        mExitAnimator.start(fromView);
        cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
            @Override
            public void onCancel() {
                mEnterAnimator.end();
                mExitAnimator.end();
            }
        });
    }

    @Override
    public void executePopChangeCancelable(AnimationInfo fromInfo, AnimationInfo toInfo, final Runnable endAction, CancellationSignal cancellationSignal) {
        final Component fromView = fromInfo.mSceneView;
        final Component toView = toInfo.mSceneView;

        AnimatorUtility.resetViewStatus(fromView);
        AnimatorUtility.resetViewStatus(toView);

        fromView.setVisibility(Component.VISIBLE);

        mAnimationViewGroup.addComponent(fromView);

        Runnable animationEndAction = new CountRunnable(2, new Runnable() {
            @Override
            public void run() {
                AnimatorUtility.resetViewStatus(fromView);
                AnimatorUtility.resetViewStatus(toView);

                mAnimationViewGroup.removeComponent(fromView);
                endAction.run();
            }
        });

        mEnterAnimator = AnimationOrAnimator.loadAnimation(ability, mPopEnter);
        mExitAnimator = AnimationOrAnimator.loadAnimation(ability, mPopExit);

        mEnterAnimator.addEndAction(animationEndAction);
        mExitAnimator.addEndAction(animationEndAction);

        mEnterAnimator.start(toView);
        mExitAnimator.start(fromView);
        cancellationSignal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
            @Override
            public void onCancel() {
                mEnterAnimator.end();
                mExitAnimator.end();
            }
        });
    }

    private static class CountRunnable implements Runnable {
        int count;
        Runnable runnable;

        private CountRunnable(int count, Runnable runnable) {
            this.count = count;
            this.runnable = runnable;
        }

        @Override
        public void run() {
            count--;
            if (count == 0) {
                runnable.run();
            }
        }
    }
}
